#ifndef __ZUI_H
#define __ZUI_H

#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>

using namespace std;

typedef enum
{
	Gray, Red, Green, Yellow,
	Blue, Pink, Cyan, White, bgWhite
}	color;


#if defined(_WINDOWS_) || defined(_WIN32)
#	include <windows.h>
#	include <conio.h>
#	define cls system("cls");
#	define sleep_ms(x) Sleep(x);

	void gotoxy(int x, int y)
	{
		HANDLE handle;
		COORD coord;
		coord.X = x;
		coord.Y = y;
		handle = GetStdHandle(STD_OUTPUT_HANDLE);
		SetConsoleCursorPosition(handle, coord);
	}
		
	static inline string gray(const char* str)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 8);
		cout<<str;
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
		return "";
	}
	static inline string red(const char* str)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
		cout<<str;
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
		return "";
	}
	static inline string green(const char* str)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 10);
		cout<<str;
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
		return "";
	}
	static inline string yellow(const char* str)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14);
		cout<<str;
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
		return "";
	}
	
	static inline string blue(const char* str)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 9);
		cout<<str;
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
		return "";
	}
	
	static inline string pink(const char* str)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 13);
		cout<<str;
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
		return "";
	}
	
	static inline string cyan(const char* str)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 11);
		cout<<str;
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
		return "";
	}
		
	static inline string white(const char* str)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
		cout<<str;
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
		return "";
	}
	
	static inline string backWhite(const char* str)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 240);
		cout<<str;
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
		return "";
	}
		
	static inline string draw(string str, color colour)
	{
		switch(colour)
		{
			case Gray:
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 8);
				cout<<str;
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
			break;
			case Red:
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
				cout<<str;
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
			break;
			case Green:
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 10);
				cout<<str;
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
			break;
			case Yellow:
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14);
				cout<<str;
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
			break;
			case Blue:
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 9);
				cout<<str;
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
			break;
			case Pink:
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 13);
				cout<<str;
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
			break;
			case Cyan:
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 11);
				cout<<str;
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
			break;
			case White:
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
				cout<<str;
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
			break;
			case bgWhite:
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 240);
				cout<<str;
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
			break;
		}
		return "";
	}

#	define GOTOXY(x,y) gotoxy(x,y)
/*-----------------------------------------------------------*/
#else
#	ifdef __ANDROID__
#		include <conio.h>
#	else
		inline int getch(void)
		{
			int c;
			system("stty -echo");
			system("stty -icanon");
			c = getchar();
			system("stty icanon");
			system("stty echo");
			return c;
		}
		
		inline int getche(void)
		{
			int c;
			system("stty -icanon");
			c = getchar();
			system("stty icanon");
			return c;
		}
		void gotoxy(int x,int y)
		{ 
 			printf("%c[%d;%df",0x1B,y,x); 
		}
#	endif

#	define gray(x)		"\033[1m\033[40;30m" x "\033[0m"
#	define red(x)		"\033[1m\033[40;31m" x "\033[0m"
#	define green(x)		"\033[1m\033[40;32m" x "\033[0m"
#	define yellow(x)	"\033[1m\033[40;33m" x "\033[0m"
#	define blue(x) 		"\033[1m\033[40;34m" x "\033[0m"
#	define pink(x)		"\033[1m\033[40;35m" x "\033[0m"
#	define cyan(x)		"\033[1m\033[40;36m" x "\033[0m"
#	define white(x)		"\033[1m\033[40;37m" x "\033[0m"
#	define backWhite(x) "\033[1m\033[47;30m" x "\033[0m"

#	define cls system("clear");
#	define sleep_ms(x) usleep((x) * 1000)
#	define GOTOXY(x,y) gotoxy((x)+1,(y)+1)
	
	static inline string draw(string str, color colour)
	{
		switch(colour)
		{
			case Gray:
				str = "\033[1m\033[40;30m" + str + "\033[0m";
			break;
			case Red:
				str = "\033[1m\033[40;31m" + str + "\033[0m";
			break;
			case Green:
				str = "\033[1m\033[40;32m" + str + "\033[0m";
			break;
			case Yellow:
				str = "\033[1m\033[40;33m" + str + "\033[0m";
			break;
			case Blue:
				str = "\033[1m\033[40;34m" + str + "\033[0m";
			break;
			case Pink:
				str = "\033[1m\033[40;35m" + str + "\033[0m";
			break;
			case Cyan:
				str = "\033[1m\033[40;36m" + str + "\033[0m";
			break;
			case White:
				str = "\033[1m\033[40;37m" + str + "\033[0m";
			break;
			case bgWhite:
				str = "\033[1m\033[47;30m" + str + "\033[0m";
			break;
		}
		return str;
	}
	
	ostream& operator << (ostream& ost, color colour)
	{
		ost << "\033[1m\033[4";
		if(colour < bgWhite)
		{
			ost << "0;3" << (char)((int)colour + '0') << 'm';
		}
		else
		{
			ost << "7;3" << (char)((int)colour - (int)bgWhite + '0') << 'm';
		}
		
		return ost;
	}
	#define colorEnd "\033[0m"
#endif

static inline void box
(
	unsigned char posX,
	unsigned char posY,
	unsigned char sizX,
	unsigned char sizY,
	color		  colour = White
)
{
	if(sizY < 3) sizY = 3;
	GOTOXY(posX, posY);
	cout<<" ";
	
	for(register unsigned char i=0 ; i<sizX-2 ; ++i)
	{
		switch(colour)
		{
			case Gray:cout<<  gray("=");	break;
			case Red:cout<<   red("=");		break;
			case Green:cout<< green("=");	break;
			case Yellow:cout<<yellow("=");	break;
			case Blue:cout<<  blue("=");	break;
			case Pink:cout<<  pink("=");	break;
			case Cyan:cout<<  cyan("=");	break;
			case White:cout<<white("=");	break;
			case bgWhite:cout<<backWhite("=");break;
		}
	}

	for(register unsigned char i=0 ; i<sizY-2 ; ++i)
	{
		GOTOXY(posX, posY+i+1);
		switch(colour)
		{
			case Gray:cout<<  gray("|");	break;
			case Red:cout<<   red("|");		break;
			case Green:cout<< green("|");	break;
			case Yellow:cout<<yellow("|");	break;
			case Blue:cout<<  blue("|");	break;
			case Pink:cout<<  pink("|");	break;
			case Cyan:cout<<  cyan("|");	break;
			case White:cout<<white("|");	break;
			case bgWhite:cout<<backWhite("=");break;
		}
		
		GOTOXY(posX+sizX-1, posY+i+1);
			
		switch(colour)
		{
			case Gray:cout<<  gray("|");	break;
			case Red:cout<<   red("|");		break;
			case Green:cout<< green("|");	break;
			case Yellow:cout<<yellow("|");	break;
			case Blue:cout<<  blue("|");	break;
			case Pink:cout<<  pink("|");	break;
			case Cyan:cout<<  cyan("|");	break;
			case White:cout<<white("|");	break;
			case bgWhite:cout<<backWhite("=");break;
		}
	}
	
	GOTOXY(posX, posY+sizY-1);
	cout<<" ";
	for(register unsigned char i=0 ; i<sizX-2 ; ++i)
	{
		switch(colour)
		{
			case Gray:cout<<  gray("=");	break;
			case Red:cout<<   red("=");		break;
			case Green:cout<< green("=");	break;
			case Yellow:cout<<yellow("=");	break;
			case Blue:cout<<  blue("=");	break;
			case Pink:cout<<  pink("=");	break;
			case Cyan:cout<<  cyan("=");	break;
			case White:cout<<white("=");	break;
			case bgWhite:cout<<backWhite("=");break;
		}
	}

	GOTOXY(posX+2, posY+1);
}

static inline void textLine
(
	unsigned char posX,
	unsigned char posY,
	unsigned char sizX,
	unsigned char sizY,
	color		  colour = White
)
{
	if(sizY < 3) sizY = 3;
	GOTOXY(posX, posY);
	cout<<" ";
	
	GOTOXY(posX, posY+sizY-1);
	cout<<" ";
	for(register unsigned char i=0 ; i<sizX-2 ; ++i)
	{
		switch(colour)
		{
			case Gray:cout<<  gray("_");	break;
			case Red:cout<<   red("_");		break;
			case Green:cout<< green("_");	break;
			case Yellow:cout<<yellow("_");	break;
			case Blue:cout<<  blue("_");	break;
			case Pink:cout<<  pink("_");	break;
			case Cyan:cout<<  cyan("_");	break;
			case White:cout<<white("_");	break;
			case bgWhite:cout<<backWhite("_");break;
		}
	}

	GOTOXY(posX+2, posY+1);
}

#endif
